package com.adee.juc;

import com.adee.util.Utils;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Test004_ReentrantLock_synchronized {
    static int i = 0;

    public static void main(String[] args) throws Exception {
        // testReentrantLock();
        // 测试 ReentrantLock性能
        test(ReentrantLockTask.class, 10, 20, 100, 100, 10);
        // 测试 synchronized性能
        test(SynchronizedTask.class, 10, 20, 100, 100, 10);
    }

    /**
     *
     * @param c
     * @param times 总体测试次数
     * @param threads 每次测试启用线程数
     * @param tasks 每次测试总任务数
     * @param lockOps 每个任务执行锁操作次数
     * @param us 模拟单次锁操作耗时，微秒
     * @throws Exception
     */
    public static void test(Class<? extends Runnable> c, int times, int threads, int tasks, int lockOps, int us) throws Exception{
        System.out.println("测试" + c.getSimpleName() + ": ");
        long all = 0;
        for (int j = 0; j < times; j++) {
            long t = byLock(c, threads, tasks, lockOps, us);
            all += t;
            System.out.print(t + ",");
        }
        System.out.println("平均耗时：" + (all/times));
    }

    // ReentrantLock与Synchronized性能对比
    public static long byLock(Class<? extends Runnable> c, int threads, int tasks, int lockOps, int us) throws Exception{
        ExecutorService tp = Executors.newFixedThreadPool(threads);
        Utils.sleep(1);
        CountDownLatch latch = new CountDownLatch(tasks);
        ReentrantLock lock = new ReentrantLock();
        long begin = System.currentTimeMillis();
        for (int j = 0; j < tasks; j++) {
            tp.execute(c.getConstructor(CountDownLatch.class, Lock.class, int.class, int.class)
                    .newInstance(latch, lock, lockOps, us));
        }
        latch.await();
        long end = System.currentTimeMillis();
        //System.out.println("i: " + i);
        // 575 539 549 543 521
        //System.out.println(c.getSimpleName() + " 耗时：" + (end-begin) + "ms");
        tp.shutdown();
        Utils.sleep(2);
        return end-begin;
    }

    // 使用ReentranLock锁的任务
    static class ReentrantLockTask implements Runnable {
        private CountDownLatch latch;
        private Lock lock;
        private int lockOps;
        private int millis;
        public ReentrantLockTask(CountDownLatch latch, Lock lock, int lockOps, int millis){
            this.latch = latch;
            this.lock = lock;
            this.lockOps = lockOps;
            this.millis = millis;
        }
        @Override
        public void run() {
            int m = millis;
            int ops = lockOps;
            for (int j = 0; j < ops; j++) {
                lock.lock();
                try {
                    i++;
                    if(m > 0) {
                        try {
                            TimeUnit.MICROSECONDS.sleep(m);
                            //TimeUnit.MILLISECONDS.sleep(m);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                } finally {
                    lock.unlock();
                }
            }
            latch.countDown();
        }
    }
    // 使用synchronized锁的任务
    static class SynchronizedTask implements Runnable {
        private CountDownLatch latch;
        private Lock lock;
        private int lockOps;
        private int millis;
        public SynchronizedTask(CountDownLatch latch, Lock lock, int lockOps, int millis){
            this.latch = latch;
            this.lock = lock;
            this.lockOps = lockOps;
            this.millis = millis;
        }
        @Override
        public void run() {
            int m = millis;
            int ops = lockOps;
            for (int j = 0; j < ops; j++) {
                synchronized (Test004_ReentrantLock_synchronized.class) {
                    i++;
                    if(m > 0) {
                        try {
                            TimeUnit.MICROSECONDS.sleep(m);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
            latch.countDown();
        }
    }
    // ReentrantLock使用
    public static void testReentrantLock() throws InterruptedException {
        ReentrantLock lock = new ReentrantLock();
        Thread t1 = new Thread(() -> {
            for (int j = 0; j < 10000; j++) {
                lock.lock();
                try {
                    i++;
                } finally {
                    lock.unlock();
                }
            }
        });
        Thread t2 = new Thread(() -> {
            for (int j = 0; j < 10000; j++) {
                lock.lock();
                try {
                    i++;
                } finally {
                    lock.unlock();
                }
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println("i: " + i);
    }
}
